Batch fix: #11-#16, #18 (untested, needs live device pass) - #18
Draft
dubpixel wants to merge 8 commits into
Draft
Conversation
Found 12.1 GiB of already-expired-but-uncollected artifacts via the API, deleted them manually, and logged the recurring fix (delete CI artifacts after they land in a release) as a housekeeping item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Card was single-width at 17px monospace, which wraps mid-octet on a full IPv4 address (word-break:break-all). Matches the existing Hostname card's span-2 treatment for another field with unpredictable length. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
companion-dashboard's main.js checks process.argv.includes('--kiosk-mode'),
not '--kiosk' -- the wrong flag meant kiosk mode (fullscreen + the
auto-started :80 web server) never actually triggered. Confirmed against
upstream source, not guessed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Depends on #13's fix landing first -- companion-dashboard only auto-starts its /control web server (port 80) when real kiosk mode is detected. Link only shown while the kiosk service is actually active (dashboard_enabled() == svc_active), same gating as the existing Toggle Fullscreen button. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
toggle_net()/pin_static() -- the functions the deck's NET key drives -- called write_networkd_config() unconditionally, writing systemd-networkd files and restarting systemd-networkd. On Raspberry Pi OS, which ships NetworkManager by default, that does nothing durable: NetworkManager keeps managing the interface and reasserts its own connection profile's DHCP setting on next boot, which is exactly the "has to be reselected every boot" behavior reported. The manual /network web form already branched on nmcli_available() vs networkd correctly -- the deck-driven functions never got the same treatment. Added write_nmcli_config() (nmcli connection modify, which persists straight to the on-disk profile) and an apply_net_config() dispatcher, and pointed toggle_net()/pin_static() at the dispatcher instead of the networkd-only function directly. get_current_net_mode() in dpx-deck-splash.py already reads live kernel state via `ip addr`, so it correctly reflects whichever backend actually applied the change -- no read-side fix needed, this was write-path only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
#11, #12) Two related gaps, one mechanism, per the design decision to solve them together rather than as separate bolted-on fixes: - #11: nothing brought dpx-deck-splash.service back once a mode service's own Restart=on-failure exhausted its StartLimitBurst -- the deck just went dark/stale forever. Fixed with OnFailure=dpx-deck-splash.service drop-ins on all three mode units (as .service.d/ overrides, not direct edits, since they ship from vendor .deb packages). OnFailure= only fires once a unit's ActiveState actually reaches "failed" -- systemd holds it in "activating (auto-restart)" between individual retries -- so this is inherently once-per-real-outage, not once-per-retry. Event-driven, no polling. - #12: dpx-deck-splash.service and the persisted mode service were both WantedBy=multi-user.target, racing at boot with Conflicts= picking whichever won -- confirmed nondeterministic on hardware ("sometimes splash wins and blocks it without a GO press"). Fixed with a new dpx-mode-select.service oneshot that reads /etc/dpx-mode at boot and starts exactly that one service, falling back to the splash only if nothing's persisted or the target refuses to start. Splash is no longer auto-enabled on its own, so there's nothing left to race. Not live-verified yet -- no device access this pass. Needs a real boot-cycle test and a forced-permanent-failure test once hardware is available; also worth rechecking the "GO does nothing" symptom against this fix, since execute_staged()'s existing mode_dead check already looks correct on paper and may have been a downstream effect of the same race rather than its own bug. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two layers: release-action.yaml's release job now deletes its own run's CI artifacts right after they land in the GitHub Release (they're redundant once the .img.gz is a real release asset). New weekly artifact-sweep.yaml workflow catches everything else -- stray feature- branch/debug builds that never go through the release job -- by deleting anything already past its own expires_at, since GitHub's own cleanup can lag by weeks in practice (confirmed this session: found and manually cleared 12.1GiB that was up to three weeks overdue). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…10) Root cause found via live SSH investigation on dpx-buttonode-2199 (rockpi-s), confirmed with three isolated tests: 1. udev_retrigger() alone (what switch_mode() actually called) does NOT recreate /dev/hidraw* once a libusb consumer (Buttons/Satellite/ deck-splash) has detached the kernel driver to claim the device -- verified by running it in isolation and confirming hidraw stayed missing. 2. The full unbind/bind (usb_power_cycle(), already built and already wired into the manual /power-cycle-deck button) DOES recreate it -- verified live. 3. With hidraw present, Companion picks up the Stream Deck cleanly at startup ("Surface panel ready: streamdeck:..."). Companion's surface module only scans once at startup and never retries, so if hidraw is missing at that exact moment, Companion silently finds nothing -- this is why the reported symptom looked intermittent/mode-switch- specific rather than a permissions problem. Fix: switch_mode() now calls the same usb_power_cycle() fallback /power-cycle-deck already used manually, instead of the gentle-only udev_retrigger(). usb_power_cycle() already tries the gentle retrigger first and only escalates to the disruptive unbind/bind if that alone wasn't enough, so this is a safe drop-in with no added cost in the common case. Verified end-to-end on real hardware: forced hidraw missing via deck-splash, ran the actual --apply-mode companion production path with the fix applied, hidraw came back automatically, Companion started and opened the surface panel successfully. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements everything from ACTION-PLAN.md that's verifiable without live hardware:
--kiosk→--kiosk-mode(confirmed root cause against upstream source)/controllink in web UI (depends on feat: Dashboard should start full screen #13)toggle_net()/pin_static()were networkd-only, added an nmcli-aware dispatcherOnFailure=drop-ins, event-driven per design decisiondpx-mode-select.servicepicks exactly one, deterministicallyNot done here (need live device access)
Test plan
py_compile,bash -n) — done/controllink resolves after feat: Dashboard should start full screen #13 (feat: Dashboard should start full screen #13, feat: Dashboard link in DPX web interface #15)🤖 Generated with Claude Code